﻿using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using WebsiteLoadTool.Configuration;
using WebsiteLoadTool.Worker;

namespace WebsiteLoadTool
{
    public class MainViewModel : NotificationObject
    {
        private DelegateCommand closeCommand;

        private DelegateCommand showLogCommand;
        private DelegateCommand showConfigurationCommand;

        private DelegateCommand startTimerCommand;
        private DelegateCommand stopTimerCommand;

        private DelegateCommand checkSelectedWebsiteCommand;

        private ObservableCollection<Website> websites;
        private Website selectedWebsite;

        private StringBuilder logTextBuilder;

        private DateTime timerStart;
        private TimeSpan timerDuration;
        private bool timerStarted;
        private int ticksHandled = 0;

        private DispatcherTimer timer;

        private DispatcherTimer durationTimer;


        public MainViewModel()
        {
            timer = new DispatcherTimer(DispatcherPriority.Background);
            timer.Tick += Tick;

            durationTimer = new DispatcherTimer(DispatcherPriority.Background);
            durationTimer.Interval = System.TimeSpan.FromSeconds(1);
            durationTimer.Tick += DurationTimerTick;

            logTextBuilder = new StringBuilder();

            TimerDuration = new TimeSpan();

            CloseCommand = new DelegateCommand(Close);
            ShowLogCommand = new DelegateCommand(ShowLog);
            ShowConfigurationCommand = new DelegateCommand(ShowConfiguration);

            StartTimerCommand = new DelegateCommand(StartTimer, CanStartTimer);
            StopTimerCommand = new DelegateCommand(StopTimer, CanStopTimer);

            CheckSelectedWebsiteCommand = new DelegateCommand(CheckSelectedWebsite, CanCheckSelectedWebsite);
        }


        public ObservableCollection<Website> Websites
        {
            get { return websites; }
            set
            {
                if (!ObservableCollection<Website>.Equals(websites, value))
                {
                    websites = value;
                    RaisePropertyChanged("Websites");
                }
            }
        }

        public Website SelectedWebsite
        {
            get { return selectedWebsite; }
            set
            {
                if (!Website.Equals(selectedWebsite, value))
                {
                    selectedWebsite = value;
                    RaisePropertyChanged("SelectedWebsite");

                    CheckSelectedWebsiteCommand.RaiseCanExecuteChanged();
                }
            }
        }


        public string LogText
        {
            get { return logTextBuilder.ToString(); }
        }

        public DateTime TimerStart
        {
            get { return timerStart; }
            set
            {
                if (!DateTime.Equals(timerStart, value))
                {
                    timerStart = value;
                    RaisePropertyChanged("TimerStart");
                }
            }
        }

        public TimeSpan TimerDuration
        {
            get { return timerDuration; }
            set
            {
                if (!TimeSpan.Equals(timerDuration, value))
                {
                    timerDuration = value;
                    RaisePropertyChanged("TimerDuration", "TimerDurationString");
                }
            }
        }

        public string TimerDurationString
        {
            get { return string.Format("{0:dd\\:hh\\:mm\\:ss}", TimerDuration); }
        }

        public bool TimerStarted
        {
            get { return timerStarted; }
            set
            {
                if (!bool.Equals(timerStarted, value))
                {
                    timerStarted = value;
                    RaisePropertyChanged("TimerStarted");
                }
            }
        }

        public int TicksHandled
        {
            get { return ticksHandled; }
            set
            {
                if (!int.Equals(ticksHandled, value))
                {
                    ticksHandled = value;
                    RaisePropertyChanged("TicksHandled");
                }
            }
        }


        public DelegateCommand CloseCommand
        {
            get { return closeCommand; }
            set
            {
                if (!DelegateCommand.Equals(closeCommand, value))
                {
                    closeCommand = value;
                    RaisePropertyChanged("CloseCommand");
                }
            }
        }

        public DelegateCommand ShowLogCommand
        {
            get { return showLogCommand; }
            set
            {
                if (!DelegateCommand.Equals(showLogCommand, value))
                {
                    showLogCommand = value;
                    RaisePropertyChanged("ShowLogCommand");
                }
            }
        }

        public DelegateCommand ShowConfigurationCommand
        {
            get { return showConfigurationCommand; }
            set
            {
                if (!DelegateCommand.Equals(showConfigurationCommand, value))
                {
                    showConfigurationCommand = value;
                    RaisePropertyChanged("ShowConfigurationCommand");
                }
            }
        }

        public DelegateCommand StartTimerCommand
        {
            get { return startTimerCommand; }
            set
            {
                if (!DelegateCommand.Equals(startTimerCommand, value))
                {
                    startTimerCommand = value;
                    RaisePropertyChanged("StartTimerCommand");
                }
            }
        }

        public DelegateCommand StopTimerCommand
        {
            get { return stopTimerCommand; }
            set
            {
                if (!DelegateCommand.Equals(stopTimerCommand, value))
                {
                    stopTimerCommand = value;
                    RaisePropertyChanged("StopTimerCommand");
                }
            }
        }

        public DelegateCommand CheckSelectedWebsiteCommand
        {
            get { return checkSelectedWebsiteCommand; }
            set
            {
                if (!DelegateCommand.Equals(checkSelectedWebsiteCommand, value))
                {
                    checkSelectedWebsiteCommand = value;
                    RaisePropertyChanged("CheckSelectedWebsiteCommand");
                }
            }
        }


        private void Close()
        {
            Application.Current.Shutdown(0);
        }

        private void ShowLog()
        {
            try
            {
                string logPath = ConfigSettingHelper.ReadSetting("LogPath");
                Process.Start(logPath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Error", MessageBoxButton.OK, MessageBoxImage.Exclamation);
            }
        }

        private void ShowConfiguration()
        {
            ConfigurationWindowView configurationWindow = new ConfigurationWindowView()
            {
                Owner = Application.Current.MainWindow
            };

            bool? result = configurationWindow.ShowDialog();

            if (result.HasValue && result.Value)
            {
                Websites = DataFileHelper.LoadWebsites();
                DataFileHelper.LoadWebsiteResults(Websites);
                timer.Interval = System.TimeSpan.FromSeconds(int.Parse(ConfigSettingHelper.ReadSetting("Interval")));

                SelectedWebsite = null;
            }
        }


        private bool CanStartTimer()
        {
            return (timer != null && !timer.IsEnabled);
        }

        private void StartTimer()
        {
            foreach (Website site in websites)
                WebsiteLoader.Load(site, WriteLog);

            timer.Start();

            durationTimer.Start();

            TicksHandled = 1;
            TimerStart = DateTime.Now;
            TimerStarted = true;

            WriteLog("Timer started");

            StartTimerCommand.RaiseCanExecuteChanged();
            StopTimerCommand.RaiseCanExecuteChanged();
        }

        private bool CanStopTimer()
        {
            return (timer != null && timer.IsEnabled);
        }

        private void StopTimer()
        {
            timer.Stop();

            durationTimer.Stop();

            TimerStarted = false;

            WriteLog(string.Format("Timer stopped after {0:c} handeling {1} tests.", DateTime.Now.Subtract(TimerStart), TicksHandled));

            StartTimerCommand.RaiseCanExecuteChanged();
            StopTimerCommand.RaiseCanExecuteChanged();
        }

        private bool CanCheckSelectedWebsite()
        {
            return (Websites != null && SelectedWebsite != null);
        }

        private void CheckSelectedWebsite()
        {
            WebsiteLoader.Load(SelectedWebsite, WriteLog);
        }


        private void DurationTimerTick(object sender, EventArgs e)
        {
            TimerDuration = DateTime.Now.Subtract(TimerStart);
        }


        public void Loaded()
        {
            WriteLog("Application started");

            Websites = DataFileHelper.LoadWebsites();
            DataFileHelper.LoadWebsiteResults(Websites);

            timer.Interval = System.TimeSpan.FromSeconds(int.Parse(ConfigSettingHelper.ReadSetting("Interval")));

            if (bool.Parse(ConfigSettingHelper.ReadSetting("StartWithApplication")))
                StartTimer();

            StartTimerCommand.RaiseCanExecuteChanged();
            StopTimerCommand.RaiseCanExecuteChanged();
        }

        public void Unloaded()
        {
            StopTimer();

            timer.Tick -= Tick;
            durationTimer.Tick -= DurationTimerTick;

            DataFileHelper.WriteWebsites(Websites);


            WriteLog("Application closed");
        }


        private void WriteLog(string message)
        {
            string entry = string.Format("{0:dd-MM-yyyy HH:mm:ss}  |  {1}", DateTime.Now, message);

            if (bool.Parse(ConfigSettingHelper.ReadSetting("UseLog")))
                DataFileHelper.WriteLogEntry(entry);

            logTextBuilder.AppendFormat("{0}{1}", entry, System.Environment.NewLine);
            RaisePropertyChanged("LogText");
        }


        private void Tick(object sender, EventArgs e)
        {
            foreach (Website site in websites)
                WebsiteLoader.Load(site, WriteLog);

            TicksHandled++;
        }
    }
}
